﻿#pragma once

#include <learn/geom/geom_nonbasis.h>

#include <functional>

namespace xi
{

namespace geom
{

template <std::size_t N> class Geom_ComposedCurve : public Geom_NonbasisCurve<N>
{
    using Vec = VecT<N, double>;

  public:
    Geom_ComposedCurve(Geom_ComposedCurve &&) = delete;

    /**
     * @brief 构造函数
     *
     * @param[in] global2Local 根据全局参数计算所属曲线和局部参数
     * @param[in] curves 曲线集合
     * @param[in] first
     * @param[in] last
     */
    Geom_ComposedCurve(std::function<std::tuple<std::size_t, double>(double)> global2Local,
                       std::vector<std::shared_ptr<Geom_Curve<N>>> &&curves, double first, double last)
        : m_global2Local(global2Local), m_curves(std::move(curves)), m_first(first), m_last(last)
    {
    }

    /**
     * @brief 获得曲线数量
     *
     * @return std::size_t
     */
    std::size_t size() const
    {
        return m_curves.size();
    }

    /**
     * @brief 获得指定段的曲线
     *
     * @param[in] i
     * @return std::shared_ptr<Geom_Curve<N>>
     */
    std::shared_ptr<Geom_Curve<N>> curve(std::size_t i) const
    {
        return m_curves[i];
    }

    /**
     * @brief 计算曲线上点的位置
     *
     * @param[in] t
     * @return Vec
     */
    Vec d0(double t) const override
    {
        auto [i, u] = m_global2Local(t);
        return m_curves[i]->d0(u);
    }

    /**
     * @brief 计算曲线上点的位置和导数
     *
     * @param[in] t
     * @return std::array<Vec, 2>
     */
    std::array<Vec, 2> d1(double t) const override
    {
        auto [i, u] = m_global2Local(t);
        return m_curves[i]->d1(u);
    }

    /**
     * @brief 计算曲线上点的位置、导数和二阶导数
     *
     * @param[in] t
     * @return std::array<Vec, 3>
     */
    std::array<Vec, 3> d2(double t) const override
    {
        auto [i, u] = m_global2Local(t);
        return m_curves[i]->d2(u);
    }

    /**
     * @brief 计算曲线上点的位置、导数、二阶导数和三阶导数
     *
     * @param[in] t
     * @return std::array<Vec, 4>
     */
    std::array<Vec, 4> d3(double t) const override
    {
        auto [i, u] = m_global2Local(t);
        return m_curves[i]->d3(u);
    }

    /**
     * @brief 起始参数
     *
     * @return double
     */
    double first_param() const override
    {
        return m_first;
    }

    /**
     * @brief 终止参数
     *
     * @return double
     */
    double last_param() const override
    {
        return m_last;
    }

    /**
     * @brief 序列化
     *
     * @return utils::Json
     */
    utils::Json dump_json() const override
    {
        utils::Json json;
        json["type"] = "composed_curve";
        json["curves"] = m_curves;
        json["first_param"] = m_first;
        json["last_param"] = m_last;
        return json;
    }

  protected:
    std::function<std::tuple<std::size_t, double>(double)> m_global2Local;
    std::vector<std::shared_ptr<Geom_Curve<N>>> m_curves;
    double m_first, m_last;
};

} // namespace geom

} // namespace xi
